/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package facilitator;

import core.CalculationException;
import core.DmuList;
import core.GlobalPdmOptimization;
import core.Optimizer;
import core.PdmOptimization;
import driver.Iron;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import util.BinaryCombinationsIterator;
import util.Util;

/**
 *
 * @author Niki
 */
public class GlobalSolver extends Solver{
public GlobalSolver(DmuList dmuList, int objectiveDmu, double[] urmWeights){
            this.dmuList = dmuList;
            this.objectiveDmu = objectiveDmu;
            this.urmWeights = urmWeights;
        }
        private double precision = 0.1E-6;

    public double getPrecision() {
        return precision;
    }

    public void setPrecision(double precision) {
        this.precision = precision;
    }
        

        /**
         *
         * @param alpha
         * @return
         */
        public PdmOptimization getOptimization(double alpha) {
            long start = System.currentTimeMillis();
            BinaryCombinationsIterator it = new BinaryCombinationsIterator(this.dmuList.outputSize);
            GlobalPdmOptimization bestOpt = null;

            List<PdmOptimization> optimizers = new ArrayList<PdmOptimization>();

            if(alpha == 0){
            try {
                GlobalPdmOptimization curr = new GlobalPdmOptimization(this.dmuList, this.objectiveDmu, alpha, this.urmWeights, it.next());
                Optimizer.calculatePdm(curr);
                curr.optimizers.add((PdmOptimization)curr);
                return curr;
            } catch (CalculationException ex) {
                Logger.getLogger(GlobalSolver.class.getName()).log(Level.SEVERE, null, ex);
            }
            }

            while(it.hasNext()){
                try {
                    GlobalPdmOptimization curr = new GlobalPdmOptimization(this.dmuList, this.objectiveDmu, alpha, this.urmWeights, it.next());
                    Optimizer.calculatePdm(curr);

                    optimizers.add(curr);
                    //old code
                    /*if(bestOpt == null){
                        bestOpt = curr; //object holder
                    }
                    Util.print(curr.getOptimizationObjective() + ";" + Arrays.toString(curr.getOptimizationDirections()));
                    if(curr.getOptimizationObjective() > bestOpt.getOptimizationObjective()+precision){
                        bestOpt = curr;
                        //Util.print("new best optimizer");
                        bestOpt.optimizers.add(curr);
                    }
                    else if(curr.getOptimizationObjective() >= (bestOpt.getOptimizationObjective()-precision)){
                        bestOpt.optimizers.add(curr);
                        //Util.print("match optimizer");
                    }
                    */

                } catch (CalculationException ex) {
                    Logger.getLogger(GlobalSolver.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            Collections.sort(optimizers, new Comparator<PdmOptimization>() {

                public int compare(PdmOptimization o1, PdmOptimization o2) {
                    try{
                        if(o1.getOptimizationObjective() < o2.getOptimizationObjective()){
                            return 1;
                        }
                        else{
                            return -1;
                        }
                    }catch(CalculationException exc){
                        Logger.getLogger(GlobalSolver.class.getName()).log(Level.SEVERE, null, exc);
                    }
                    return 0;
                }
            }
            );
            
            try {
                int i = 1;
                boolean run = true;
                bestOpt = (GlobalPdmOptimization)optimizers.get(0);
                bestOpt.optimizers.add(optimizers.get(0));
                
                while(i < optimizers.size() && run){
                    if(optimizers.get(i).getOptimizationObjective() != optimizers.get(i-1).getOptimizationObjective()
                            && (Util.isPowerTwo(i, this.urmWeights.length))){
                            run = false;
                    }
                    else{
                        bestOpt.optimizers.add(optimizers.get(i));
                        i++;
                    }
                }

            } catch (CalculationException ex) {
                Logger.getLogger(GlobalSolver.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            bestOpt.setOptimizationTime(System.currentTimeMillis() - start);
            return bestOpt;
        }
}
